package com.leon.common.util;

import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;

/**
 * 
 * 页面到VO互相转化的工具。 User user = new User(); String json =
 * ViewLayerMappingTool.object2json(user);
 * 需要注意，如果对象有相互引用，则生成的json会出现reference,尽量避免vo互相引用
 * 
 * @author lijiaz
 * 
 */
public class VVMappingUtil {

	public static XStream getXStream() {
		XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
			public HierarchicalStreamWriter createWriter(Writer writer) {
				return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
			}
		});
		xstream.registerConverter(new XSrreamDateConverter());
		// xstream.registerConverter(new XStreamMapConverter());
		// xstream.setMode(XStream.NO_REFERENCES);
		xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);
		return xstream;
	}

	public static XStream getXStreamIgnoreMap() {
		XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
			public HierarchicalStreamWriter createWriter(Writer writer) {
				return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
			}
		});
		xstream.registerConverter(new XSrreamDateConverter());
		xstream.registerConverter(new XStreamMapConverter());
		xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);
		return xstream;
	}

	public static String object2json(Object o) {
		if (o == null)
			return "{}";
		else {
			XStream xstream = getXStream();
			return xstream.toXML(o);
		}
	}

	// public static String list2json(List list) {
	// XStream xstream = getXStream();
	// return xstream.toXML(list);
	// }
	@SuppressWarnings("unchecked")
	public static String collection2json(Collection col) {
		if (col == null || col.isEmpty())
			return "{}";
		else {
			XStream xstream = getXStream();
			List list = new ArrayList(col);
			return xstream.toXML(list);
		}
	}

	public static String collection2json(List list, int max) {
		StringBuffer extendXML = new StringBuffer("{\r\n");
		extendXML.append("results:").append(max).append(",\r\n");
		extendXML.append("rows:");
		extendXML.append(collection2json(list) + "\r\n");
		extendXML.append("}");
		return extendXML.toString();
	}

	public static String map2json(Object object) {
		StringBuffer mapStr = new StringBuffer("{\r\n");
		Map map = (Map) object;
		Set set = map.keySet();
		Iterator it = set.iterator();
		while (it.hasNext()) {
			String itNext = (String) it.next();
			mapStr.append(itNext);
			mapStr.append(":\"" + map.get(itNext) + "\",");
		}
		mapStr = new StringBuffer(mapStr.substring(0, mapStr.length() - 1));
		mapStr.append("}");
		return mapStr.toString();
	}
	public static String map2Array(Object object) {
		XStream xstream = new XStream(new JsonHierarchicalStreamDriver());

		String mapStr = xstream.toXML(object);
		mapStr = mapStr.replaceFirst("linked-hash-map", "map");
		return mapStr;
	}

	/**
	 * 此方法有些问题，最好效果是Object..msgPair 由于目前没有找到合适的MapConverter，暂时手工拼写一个json串
	 * 
	 * @param isSuccess
	 * @param msg
	 * @param msgPair
	 * @return
	 */
	public static String createRsp(boolean isSuccess, String msg, String... msgPair) {
		StringBuilder sb = new StringBuilder();
		if (isSuccess) {
			sb.append("{success:true,");
		} else {
			sb.append("{success:false,");
		}

		if (msgPair.length != 0) {
			sb.append("errors:{");
			for (int i = 0; i < msgPair.length; i++) {
				sb.append(msgPair[i]).append(":\"").append(msgPair[++i]).append("\",");
			}
			sb.setLength(sb.length() - 1);
			sb.append("},");
		}
		sb.append("msg:\"").append(msg).append("\"}");
		return sb.toString();
	}

	/**
	 * 此方法有些问题，最好效果是Object..msgPair 由于目前没有找到合适的MapConverter，暂时手工拼写一个json串
	 * 
	 * @param isSuccess
	 * @param msg
	 * @param customize
	 *            (自定义json)自定义参数格式为akey:"avalue",bkey:{bkey1:bkeyValue,bkey2...}
	 *            ...
	 * @param msgPair
	 * @return
	 */
	public static String createRsp2(boolean isSuccess, String msg, String customize, String... msgPair) {
		StringBuilder sb = new StringBuilder();
		if (isSuccess) {
			sb.append("{success:true,");
		} else {
			sb.append("{success:false,");
		}
		if (msg != null)

			if (msgPair.length != 0) {
				sb.append("errors:{");
				for (int i = 0; i < msgPair.length; i++) {
					sb.append(msgPair[i]).append(":\"").append(msgPair[++i]).append("\",");
				}
				sb.setLength(sb.length() - 1);
				sb.append("},");
			}
		sb.append("msg:\"").append(msg).append("\"}");
		return sb.toString();
	}

	/*
	 * public static String createRsp(boolean isSuccess, String msg, Object...
	 * msgPair) { Rsp rsp = new Rsp(); rsp.success = isSuccess; rsp.msg = msg;
	 * if (msgPair.length != 0) {
	 * 
	 * for (int i = 0; i < msgPair.length; i++) { rsp.submsgs.add(msgPair[i]); } }
	 * return object2json(rsp); }
	 * 
	 * 
	 * static class Rsp { boolean success;
	 * 
	 * String msg;
	 * 
	 * List submsgs = new ArrayList(); }
	 */
	static {
		// 如果日期类型转换
		DateConverter d = new DateConverter();
		ConvertUtils.register(d, java.util.Date.class);
		// 如果Integer类型转换
		IntegerConverter ic = new IntegerConverter();
		ConvertUtils.register(ic, Integer.class);

		FloatCoverter fc = new FloatCoverter();
		ConvertUtils.register(fc, Float.class);

		LongCoverter lc = new LongCoverter();
		ConvertUtils.register(lc, Long.class);
	}

	public static void populate(HttpServletRequest request, Object obj) {
		Map map = request.getParameterMap();
		try {
			BeanUtils.populate(obj, map);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e.getMessage());
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e.getMessage());
		}
	}
	public static void populate(Map map,Object obj){
		try {
			BeanUtils.populate(obj, map);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e.getMessage());
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	public static void main(String[] args) {
		
	}
	/*
	 * 因为使用BeanUtils.populate(obj, map);在服务器运行2,3个小时或半天时间总是报类型转换错误，
	 * 但重启服务器后就又正常了...
	 * 不得已手动转换...还一直没找到问题所在，先手动转换再想办法吧。
	 */
	public static void map2Object(Map map,Object obj){
		
		Set set = map.keySet();
		Iterator it = set.iterator();
		while(it.hasNext()){
			String key = it.next().toString();
			Object[] value = (Object[])map.get(key);
			populateObj(obj,key,value[0]);
		};
	}
	public static void populateObj(Object obj,String pname,Object value){
		try{
			Field[] fields= obj.getClass().getFields();			
			Class cls = obj.getClass();
			fields = cls.getDeclaredFields();
			
			for(Field field:fields){
				
				String type = field.getType().getSimpleName();				
				String fname = field.getName();
				
				if(fname.equals(pname) && value!=null){
					System.out.println(fname+"==="+type+"==="+value);
					type = type.toUpperCase();				
					if(type.equals("STRING")){
						value = value.toString();
						field.setAccessible(true);
						field.set(obj,value);
						break;
					}else if(type.equals("LONG")){
						if(value!=null && !value.equals("")){
							field.setAccessible(true);
							value = Long.parseLong(value.toString());
							field.set(obj,value);							
						}
						break;
					}else if(type.equals("INTEGER")){
						if(value!=null && !value.equals("")){
							field.setAccessible(true);
							value = Integer.parseInt(value.toString());
							field.set(obj,value);
						}
						break;
					}else if(type.equals("FLOAT")){
						if(value!=null && !value.equals("")){
							field.setAccessible(true);
							BigDecimal bd = new BigDecimal(value.toString());
							field.set(obj,bd.floatValue());
						}
						break;
					}else if(type.equals("DATE")){
						if(value!=null && !value.equals("")){
							field.setAccessible(true);
							SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
							value = sd.parse((String) value);
							field.set(obj,value);
						}
						break;
					}				
				}else {					
					int pos = pname.indexOf(".");
					if(pos>-1){
						String tname = pname.substring(0,pos);
						if(tname.equals(fname)){							
							field.setAccessible(true);
							String tname2 = pname.substring(pos+1);
							System.out.println(tname2+"==="+type+"==="+value);
							Object tobj = field.get(obj);
							populateObj(tobj,tname2,value);
						}
					}
				}
				
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

class User {
	Map map = null;

	String name;

	Date date = new Date();
}

class DateConverter implements org.apache.commons.beanutils.Converter {
	public Object convert(Class type, Object value) {
		// value = value+" 02:03:05";
		// SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
		if (value == null || value.equals(""))
			return null;
		try {
			Date rvalue = sd.parse((String) value);
			return rvalue;
		} catch (ParseException e) {
			throw new RuntimeException(e.getMessage());
		}
	}
}

class IntegerConverter implements Converter {
	public Object convert(Class type, Object value) {
		try {

			if (value == null || value.equals(""))
				return null;
			return Integer.parseInt(value.toString());
		} catch (Exception ex) {
			return null;
		}
	}
}

class FloatCoverter implements Converter {
	public Object convert(Class type, Object value) {
		try {
			if (value == null || value.equals("")) {
				return null;
			} else
				return Float.parseFloat(value.toString());
		} catch (Exception e) {
			return null;
		}
	}
}

class LongCoverter implements Converter {
	public Object convert(Class type, Object value) {
		try {
			if (value == null || value.equals("")) {
				return null;
			} else
				return Long.parseLong(value.toString());
		} catch (Exception e) {
			return null;
		}
	}
}

class XSrreamDateConverter implements com.thoughtworks.xstream.converters.Converter {

	public XSrreamDateConverter() {
		super();

	}

	public boolean canConvert(Class clazz) {
		return java.util.Date.class.isAssignableFrom(clazz);
	}

	public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {

		Date date = (Date) value;
		;
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		writer.setValue(formatter.format(date));

	}

	public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {

		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

		try {
			return formatter.parse(reader.getValue());
		} catch (ParseException e) {
			throw new ConversionException(e.getMessage(), e);
		}

	}

}

class XStreamMapConverter implements com.thoughtworks.xstream.converters.Converter {

	public XStreamMapConverter() {

	}

	public boolean canConvert(Class type) {
		return type.equals(HashMap.class) || type.equals(Hashtable.class)
				|| type.getName().equals("java.util.LinkedHashMap") || type.getName().equals("sun.font.AttributeMap") // Used
		// by
		// java.awt.Font
		// in JDK 6
		;
	}

	public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {

	}

	public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
		return null;

	}

}
